﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartSpace.Core
{
    public partial class CoreService : ICoreService
    {
        private ICoreFactory _contextFactory { get; set; }

        public CoreService(ICoreFactory contextFactory)
        {
            _contextFactory = contextFactory;
        }

        public User GetUser(string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<User>()
                    .Include("Role")
                    .Where(p => p.Account == account)
                    .FirstOrDefault();
            }
        }

        public User GetUser(Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<User>()
                    .Include("Role")
                    .Where(p => p.Id == id)
                    .FirstOrDefault();
            }
        }

        public List<User> GetUsers(List<Guid> idList)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return (from order in context.Set<User>()
                              where (idList.Contains(order.Id))
                              select order).ToList();
            }
        }

        public PagedList<User> GetUsers(int start, int limit)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<User> list = context.Set<User>()
                    .OrderByDescending(p => p.Account)
                    .Skip(start)
                    .Take(limit)
                    .ToList();
                PagedList<User> pagedList = new PagedList<User>();
                foreach (User item in list)
                {
                    pagedList.Add(item);
                }
                pagedList.Start = start;
                pagedList.Limit = limit;
                pagedList.Total = context.Set<User>().Count();

                return pagedList;
            }
        }
        
        public PagedList<User> FindUsers(string filter, int start, int limit)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<User> list = context.Set<User>()
                    .Where(p=>p.Account.Contains(filter) || p.Name.Contains(filter))
                    .OrderByDescending(p => p.Account)
                    .Skip(start)
                    .Take(limit)
                    .ToList();
                PagedList<User> pagedList = new PagedList<User>();
                foreach (User item in list)
                {
                    pagedList.Add(item);
                }
                pagedList.Start = start;
                pagedList.Limit = limit;
                pagedList.Total = context.Set<User>().Where(p => p.Account.Contains(filter) || p.Name.Contains(filter)).Count();

                return pagedList;
            }
        }


        public bool SaveUser(User user)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<User>()
                    .Where(p => p.Id == user.Id)
                    .Select(p=>p.Id)
                    .FirstOrDefault() == default(Guid))
                {
                    context.Set<User>().Add(user);
                }
                else
                {
                    context.Entry(user).State = System.Data.Entity.EntityState.Modified;
                }

                context.SaveChanges();
                return true;
            }
        }

        public bool DeleteUser(User user)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<User>()
                    .Where(p => p.Id == user.Id)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() != null)
                {
                    context.Entry(user).State = System.Data.Entity.EntityState.Deleted;
                }
                context.SaveChanges();
                return true;
            }
        }

        public bool DeleteUser(Guid userId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                User user = context.Set<User>()
                    .Where(p => p.Id == userId)
                    .FirstOrDefault();

                if (user != null)
                {
                    context.Entry(user).State = System.Data.Entity.EntityState.Deleted;
                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        //public bool AssignUser(Role role, User user, User assigner)
        //{
        //    using (CoreContext context = _contextFactory.Get())
        //    {
        //        RelationRoleToUser relation = new RelationRoleToUser();
        //        relation.Id = Guid.NewGuid();
        //        relation.User = null;
        //        relation.UserId = user.Id;
        //        relation.Role = null;
        //        relation.RoleId = role.Id;
        //        relation.Assigner = null;
        //        relation.AssignerId = assigner.Id;
        //        relation.AssignedTime = DateTime.Now;

        //        if (context.Set<RelationRoleToUser>()
        //            .Where(p => p.User.Id == user.Id && p.Role.Id == role.Id)
        //            .FirstOrDefault() == null)
        //        {
        //            context.Set<RelationRoleToUser>().Add(relation);
        //            context.SaveChanges();
        //            return true;
        //        }

        //        return false;
        //    }
        //}
        
        //public bool RemoveUser(Role role, User user)
        //{
        //    using (CoreContext context = _contextFactory.Get())
        //    {
        //        RelationRoleToUser relation = context.Set<RelationRoleToUser>()
        //            .Where(p => p.Role.Id == role.Id && p.User.Id == user.Id)
        //            .FirstOrDefault();

        //        if (relation != null)
        //        {
        //            context.Set<RelationRoleToUser>().Remove(relation);
        //            context.SaveChanges();
        //            return true;
        //        }

        //        return false;
        //    }
        //}

        //public List<Role> GetAssignedRoles(User user)
        //{
        //    using (CoreContext context = _contextFactory.Get())
        //    {
        //        List<Role> roles = context.Set<Role>().Select(p => p)
        //            .Join(
        //                context.Set<RelationRoleToUser>().Where(r => r.UserId == user.Id),
        //                p => p.Id,
        //                v => v.RoleId,
        //                (p, v) => p).ToList();
        //        return roles;
        //    }
        //}

        //public List<User> GetContainsUsers(Role role)
        //{
        //    using (CoreContext context = _contextFactory.Get())
        //    {
        //        return context.Set<User>().Select(p => p)
        //            .Join(
        //                context.Set<RelationRoleToUser>().Where(r => r.Role.Id == role.Id),
        //                p => p.Id,
        //                v => v.User.Id,
        //                (p, v) => p).ToList();
        //    }
        //}

        //public List<User> GetContainsUsers(Guid roleId)
        //{
        //    using (CoreContext context = _contextFactory.Get())
        //    {
        //        return context.Set<User>().Select(p => p)
        //            .Join(
        //                context.Set<RelationRoleToUser>().Where(r => r.Role.Id == roleId),
        //                p => p.Id,
        //                v => v.User.Id,
        //                (p, v) => p).ToList();
        //    }
        //}

        public bool SaveModule(Module module)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<Module>()
                    .Where(p => p.Id == module.Id)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() == null)
                {
                    context.Set<Module>().Add(module);
                }
                else
                {
                    context.Entry(module).State = System.Data.Entity.EntityState.Modified;

                    List<ModuleView> existViews = context.Set<ModuleView>().Where(p => p.ModuleId == module.Id).ToList();
                    foreach (var existView in existViews)
                    {
                        bool isExist = false;
                        foreach (var view in module.Views)
                        {
                            if (existView.Id == view.Id)
                            {
                                existView.Caption = view.Caption;
                                existView.Name = view.Name;
                                isExist = true;
                                break;
                            }
                        }

                        if (!isExist)
                        {
                            context.Entry(existView).State = System.Data.Entity.EntityState.Deleted;
                        }
                        else
                        {
                            context.Entry(existView).State = System.Data.Entity.EntityState.Modified;
                        }
                    }

                    foreach (var view in module.Views)
                    {
                        bool isExist = false;
                        foreach (var existView in existViews)
                        {
                            if (existView.Id == view.Id)
                            {
                                isExist = true;
                                break;
                            }
                        }

                        if (!isExist)
                        {
                            context.Set<ModuleView>().Add(view);
                        }
                    }
                }

                context.SaveChanges();
                return true;
            }
        }

        public Module GetModule(Guid moduleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Module>().Where(p => p.Id == moduleId).SingleOrDefault();
            }
        }

        public PagedList<Module> GetModules(int start, int limit)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Module> list = context.Set<Module>()
                    .Include("Views")
                    .OrderByDescending(p => p.Name)
                    .Skip(start)
                    .Take(limit)
                    .ToList();
                PagedList<Module> pagedList = new PagedList<Module>();
                foreach (Module item in list)
                {
                    pagedList.Add(item);
                }
                pagedList.Start = start;
                pagedList.Limit = limit;
                pagedList.Total = context.Set<Module>().Count();

                return pagedList;
            }
        }

        public PagedList<Module> GetModules(string type, int start, int limit)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Module> list = context.Set<Module>()
                    .Include("Views")
                    .Where(p=>p.Type == type)
                    .OrderByDescending(p => p.Name)
                    .Skip(start)
                    .Take(limit)
                    .ToList();
                PagedList<Module> pagedList = new PagedList<Module>();
                foreach (Module item in list)
                {
                    pagedList.Add(item);
                }
                pagedList.Start = start;
                pagedList.Limit = limit;
                pagedList.Total = context.Set<Module>().Where(p => p.Type == type).Count();

                return pagedList;
            }
        }

        public ModuleView GetView(Guid viewId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<ModuleView>()
                    .Include("Module")
                    .Where(p => p.Id == viewId).FirstOrDefault();
            }
        }

        public bool SaveNavigation(Navigation navigation)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                // 不为空，保存的时候会报错，会将VIEW也保存。
                if (navigation.ParentId == Guid.Empty)
                {
                    navigation.ParentId = null;
                }
                
                if (navigation.IsDefault)
                {
                    // 清除现在的默认导航
                    Navigation defaultNavigation = context.Set<Navigation>()
                    .Where(p => p.ApplicationId == navigation.ApplicationId && p.IsDefault == true && p.Id != navigation.Id)
                    .FirstOrDefault();

                    if (defaultNavigation != null)
                    {
                        defaultNavigation.IsDefault = false;
                        context.Entry(defaultNavigation).State = System.Data.Entity.EntityState.Modified;
                    }
                }

                if (context.Set<Navigation>()
                    .Where(p => p.Id == navigation.Id)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() == null)
                {
                    context.Set<Navigation>().Add(navigation);
                }
                else
                {
                    context.Entry(navigation).State = System.Data.Entity.EntityState.Modified;
                }

                if (context.SaveChanges() > 0)
                {
                    return true;
                }
                return false;
            }
        }

        public Navigation GetNavigation(Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Navigation>().Where(p => p.Id == id).SingleOrDefault();
            }
        }

        public bool SetDefaultNavigation(Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                Navigation navigation = context.Set<Navigation>().Where(p => p.Id == id).SingleOrDefault();
                if (navigation == null)
                {
                    return false;
                }

                if (!navigation.IsDefault)
                {
                    navigation.IsDefault = true;
                    // 清除现在的默认导航
                    Navigation defaultNavigation = context.Set<Navigation>()
                        .Where(p => p.ApplicationId == navigation.ApplicationId && p.IsDefault == true)
                        .SingleOrDefault();

                    if (defaultNavigation != null)
                    {
                        defaultNavigation.IsDefault = false;
                        context.Entry(defaultNavigation).State = System.Data.Entity.EntityState.Modified;
                    }
                    context.Entry(navigation).State = System.Data.Entity.EntityState.Modified;

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }

                return false;
            }
        }

        public List<Navigation> GetNavigations(Guid applicationId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Navigation> roots = context.Set<Navigation>()
                    .Where(p => p.ApplicationId == applicationId && (p.ParentId == Guid.Empty || p.ParentId == null))
                    .OrderBy(p => p.SortIndex)
                    .ToList();

                Stack<Navigation> stack = new Stack<Navigation>();
                foreach (Navigation root in roots)
                {
                    stack.Push(root);
                }
                while (stack.Count > 0)
                {
                    Navigation item = stack.Pop();
                    item.Children = context.Set<Navigation>()
                        .Where(p => p.ParentId == item.Id)
                        .OrderBy(p => p.SortIndex)
                        .ToList();

                    if (item.Children != null)
                    {
                        foreach (Navigation child in item.Children)
                        {
                            stack.Push(child);
                        }
                    }
                }
                return roots;
            }
        }
       
        public Navigation GetDefaultNavigation(Guid applicationId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Navigation>()
                    .Where(p => p.ApplicationId == applicationId && p.IsDefault == true)
                    .FirstOrDefault();
            }
        }

        public bool AddRoleNavigation(Guid navigationId, Guid roleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<RoleNavigation>()
                    .Where(p => p.NavigationId == navigationId && p.RoleId == roleId)
                    .Select(p => p.Id)
                    .FirstOrDefault() == Guid.Empty)
                {
                    RoleNavigation roleNavigation = new RoleNavigation();
                    roleNavigation.Id = Guid.NewGuid();
                    roleNavigation.NavigationId = navigationId;
                    roleNavigation.RoleId = roleId;

                    context.Set<RoleNavigation>().Add(roleNavigation);

                    //Guid curId = navigationId;
                    //Guid? parentId = context.Set<Navigation>().Where(p => p.Id == curId).Select(p => p.ParentId).FirstOrDefault();
                    //while (parentId != null && parentId.Value != Guid.Empty)
                    //{
                    //    if (context.Set<RoleNavigation>()
                    //        .Where(p => p.NavigationId == parentId.Value && p.RoleId == roleId)
                    //        .Select(p => p.Id)
                    //        .FirstOrDefault() == Guid.Empty)
                    //    {
                    //        RoleNavigation parentRoleNavigation = new RoleNavigation();
                    //        parentRoleNavigation.Id = Guid.NewGuid();
                    //        parentRoleNavigation.NavigationId = parentId.Value;
                    //        parentRoleNavigation.RoleId = roleId;
                    //        context.Set<RoleNavigation>().Add(parentRoleNavigation);
                    //    }

                    //    parentId = context.Set<Navigation>().Where(p => p.Id == navigationId).Select(p => p.ParentId).FirstOrDefault();
                    //}

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public bool DeleteRoleNavigation(Guid navigationId, Guid roleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                RoleNavigation roleNavigation = context.Set<RoleNavigation>()
                    .Where(p => p.NavigationId == navigationId && p.RoleId == roleId)
                    .FirstOrDefault();

                if (roleNavigation != null)
                {
                    context.Entry(roleNavigation).State = System.Data.Entity.EntityState.Deleted;

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public bool SetRoleNavigations(List<Guid> navigationIds, Guid roleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                context.Database.ExecuteSqlCommand("delete from __RoleNavigation where RoleId={0}", roleId);

                for (int i = 0; i < navigationIds.Count; i++)
                {
                    RoleNavigation roleNavigation = new RoleNavigation();
                    roleNavigation.Id = Guid.NewGuid();
                    roleNavigation.NavigationId = navigationIds[i];
                    roleNavigation.RoleId = roleId;

                    context.Set<RoleNavigation>().Add(roleNavigation);
                }

                if (context.SaveChanges() > 0)
                {
                    return true;
                }
                return false;
            }
        }

        public List<Navigation> GetNavigations(Guid applicationId, Guid roleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Navigation> roots = context.Set<Navigation>()
                    .Join(context.Set<RoleNavigation>().Where(p=>p.RoleId == roleId),
                        outer => outer.Id,
                        inner => inner.NavigationId,
                        (outer, inner)=>outer)
                    .Where(p => p.ApplicationId == applicationId && (p.ParentId == Guid.Empty || p.ParentId == null))
                    .OrderBy(p => p.SortIndex)
                    .ToList();

                Stack<Navigation> stack = new Stack<Navigation>();
                foreach (Navigation root in roots)
                {
                    stack.Push(root);
                }
                while (stack.Count > 0)
                {
                    Navigation item = stack.Pop();
                    item.Children = context.Set<Navigation>()
                        .Join(context.Set<RoleNavigation>().Where(p => p.RoleId == roleId),
                            outer => outer.Id,
                            inner => inner.NavigationId,
                            (outer, inner) => outer)
                        .Where(p => p.ParentId == item.Id)
                        .OrderBy(p => p.SortIndex)
                        .ToList();

                    if (item.Children != null)
                    {
                        foreach (Navigation child in item.Children)
                        {
                            stack.Push(child);
                        }
                    }
                }
                return roots;
            }
        }

        public List<Navigation> GetUserNavigations(Guid applicationId, Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sql = @"select n.* from __navigation as n
 join __rolenavigation as rn on n.id = rn.navigationid
 join __relationroletouser as ru on ru.roleid = rn.roleid
where n.applicationId ={0} and ru.userid={1} ";
                List<Navigation> all = context.Database.SqlQuery<Navigation>(sql, applicationId, id).ToList();

                List<Navigation> roots = new List<Navigation>();

                for (int index = 0; index < all.Count;)
                {
                    if (all[index].ParentId == null || all[index].ParentId.Value == Guid.Empty)
                    {
                        roots.Add(all[index]);
                        all.RemoveAt(index);
                    }
                    else
                    {
                        index++;
                    }
                }

                Stack<Navigation> stack = new Stack<Navigation>();
                foreach (Navigation root in roots)
                {
                    stack.Push(root);
                }
                while (stack.Count > 0)
                {
                    Navigation item = stack.Pop();
                    item.Children = new List<Navigation>();

                    for (int index = 0; index < all.Count; )
                    {
                        if (all[index].ParentId == item.Id)
                        {
                            item.Children.Add(all[index]);
                            all.RemoveAt(index);
                        }
                        else
                        {
                            index++;
                        }
                    }

                    if (item.Children != null)
                    {
                        foreach (Navigation child in item.Children)
                        {
                            stack.Push(child);
                        }
                    }
                }
                return roots;
            }
        }

        public List<Navigation> GetUserNavigations(Guid applicationId, string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sql = @"select n.* from __navigation as n
 join __rolenavigation as rn on n.id = rn.navigationid
 join __relationroletouser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
where n.applicationId ={0} and u.account={1} ";
                List<Navigation> all = context.Database.SqlQuery<Navigation>(sql, applicationId, account).ToList();

                List<Navigation> roots = new List<Navigation>();

                for (int index = 0; index < all.Count; )
                {
                    if (all[index].ParentId == null || all[index].ParentId.Value == Guid.Empty)
                    {
                        roots.Add(all[index]);
                        all.RemoveAt(index);
                    }
                    else
                    {
                        index++;
                    }
                }

                Stack<Navigation> stack = new Stack<Navigation>();
                foreach (Navigation root in roots)
                {
                    stack.Push(root);
                }
                while (stack.Count > 0)
                {
                    Navigation item = stack.Pop();
                    item.Children = new List<Navigation>();

                    for (int index = 0; index < all.Count; )
                    {
                        if (all[index].ParentId == item.Id)
                        {
                            item.Children.Add(all[index]);
                            all.RemoveAt(index);
                        }
                        else
                        {
                            index++;
                        }
                    }

                    if (item.Children != null)
                    {
                        foreach (Navigation child in item.Children)
                        {
                            stack.Push(child);
                        }
                    }
                }
                return roots;
            }
        }

        #region
        public bool AddShortcut(Guid navigationId, string caption)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                Navigation navigation = context.Set<Navigation>()
                    .Where(p=>p.Id == navigationId)
                    .SingleOrDefault();

                if (navigation != null && context.Set<Shortcut>()
                    .Where(p => p.NavigationId == navigationId)
                    .Select(p => p.Id)
                    .FirstOrDefault() == Guid.Empty)
                {
                    Shortcut shortcut = new Shortcut();
                    shortcut.Id = Guid.NewGuid();
                    shortcut.NavigationId = navigationId;
                    if (string.IsNullOrEmpty(caption))
                    {
                        shortcut.Caption = navigation.Caption;
                    }
                    else
                    {
                        shortcut.Caption = caption;
                    }

                    context.Set<Shortcut>().Add(shortcut);

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public bool DeleteShortcut(Guid navigationId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                Shortcut shortcut = context.Set<Shortcut>()
                    .Where(p => p.NavigationId == navigationId)
                    .SingleOrDefault();

                if (shortcut != null)
                {
                    context.Entry(shortcut).State = System.Data.Entity.EntityState.Deleted;

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public List<Shortcut> GetShortcuts(Guid applicationId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Shortcut> shortcuts = context.Set<Shortcut>()
                    .Join(context.Set<Navigation>().Where(p => p.ApplicationId == applicationId),
                        shortcut => shortcut.NavigationId,
                        navigation => navigation.Id,
                        (shortcut, navigation) => shortcut)
                    .ToList();

                return shortcuts;
            }
        }

        public List<Shortcut> GetShortcuts(Guid applicationId, Guid roleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Shortcut> shortcuts = context.Set<Shortcut>()
                    .Join(context.Set<Navigation>().Join(context.Set<RoleNavigation>().Where(p => p.RoleId == roleId), nv => nv.Id, rn => rn.NavigationId, (nv, rn) => nv).Where(p => p.ApplicationId == applicationId),
                        shortcut => shortcut.NavigationId,
                        navigation => navigation.Id,
                        (shortcut, navigation) => shortcut)
                    .ToList();

                return shortcuts;
            }
        }

        public List<Shortcut> GetUserShortcuts(Guid applicationId, Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sql = @"select s.* from __shortcut as s
 join __navigation as n on n.id = s.navigationid
 join __rolenavigation as rn on rn.navigationid = s.navigationid
 join __relationroletouser as ru on ru.roleid = rn.roleid
where n.applicationId ={0} and ru.userid ={1} ";
                List<Shortcut> shortcuts = context.Database.SqlQuery<Shortcut>(sql, applicationId, id).ToList();

                return shortcuts;
            }
        }

        public List<Shortcut> GetUserShortcuts(Guid applicationId, string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sql = @"select s.* from __shortcut as s
 join __navigation as n on n.id = s.navigationid
 join __rolenavigation as rn on rn.navigationid = s.navigationid
 join __relationroletouser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
where n.applicationId ={0} and u.account = {1} ";
                List<Shortcut> shortcuts = context.Database.SqlQuery<Shortcut>(sql, applicationId, account).ToList();

                return shortcuts;
            }
        }

        #endregion

        public Role GetRole(Guid roleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Role>().Where(p => p.Id == roleId).FirstOrDefault();
            }
        }

        #region application
        public bool SaveApplication(Application app)
        {
            Logger.Info("core", string.Format("begin save application:{0}", app.Id));

            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<Application>()
                    .Where(p => p.Id == app.Id)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() == null)
                {
                    Logger.Info("core", string.Format("application:{0} does not exist in database, excute insert", app.Id));
                    context.Set<Application>().Add(app);
                }
                else
                {
                    Logger.Info("core", string.Format("application:{0} exist in database, excute updae", app.Id));
                    context.Entry(app).State = System.Data.Entity.EntityState.Modified;
                }

                if (app.IsDefault)
                {
                    Application defaultApp = context.Set<Application>().Where(p => p.IsDefault == true).SingleOrDefault();
                    if (defaultApp != null && defaultApp.Id != app.Id)
                    {
                        Logger.Info("core", string.Format("setting application:{0} to default, undo application:{1}", app.Id, defaultApp.Id));
                        defaultApp.IsDefault = false;
                        context.Entry(defaultApp).State = System.Data.Entity.EntityState.Modified;
                    }
                }

                if (context.SaveChanges() > 0)
                {
                    Logger.Info("core", string.Format("save application:{0} success", app.Id));
                    return true;
                }
                else
                {
                    Logger.Error("core", string.Format("save application:{0} failure", app.Id));
                    return false;
                }
            }
        }

        public Application GetApplication(Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Application>()
                    .Where(p => p.Id == id)
                    .FirstOrDefault();
            }
        }

        public List<Application> GetApplications()
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Application>()
                    .OrderBy(p => p.SortIndex).ToList();
            }
        }

        public List<Application> GetPersonalApplications(string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sql = @"select a.* from __application as a
 join __navigation as n on n.applicationid = a.id
 join __roleNavigation as rn on rn.navigationid = n.id
 join __relationRoleToUser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
 where u.account={0}";
                return context.Database.SqlQuery<Application>(sql, account).ToList();
            }
        }

        public Application GetPersonalDefaultApplication(string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sqlDefault = @"select top 1 a.* from __application as a
 join __navigation as n on n.applicationid = a.id
 join __roleNavigation as rn on rn.navigationid = n.id
 join __relationRoleToUser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
 where u.account={0} and a.isDefault={1}";
                string sqlTop1 = @"select top 1 a.* from __application as a
 join __navigation as n on n.applicationid = a.id
 join __roleNavigation as rn on rn.navigationid = n.id
 join __relationRoleToUser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
 where u.account={0}";
                Application application = context.Database.SqlQuery<Application>(sqlDefault, account, true).SingleOrDefault();
                if (application == null)
                {
                    application = context.Database.SqlQuery<Application>(sqlTop1, account).SingleOrDefault();
                }
                return application;
            }
        }

        public List<Application> GetApplications(string type)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Application>()
                    .Where(p => p.Type == type)
                    .OrderBy(p => p.SortIndex).ToList();
            }
        }

        public List<Application> GetPersonalApplications(string type, string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sql = @"select distinct a.* from __application as a
 join __navigation as n on n.applicationid = a.id
 join __roleNavigation as rn on rn.navigationid = n.id
 join __relationRoleToUser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
 where u.account={0} and a.type={1}";
                return context.Database.SqlQuery<Application>(sql, account, type).ToList();
            }
        }

        public Application GetPersonalDefaultApplication(string type, string account)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                string sqlDefault = @"select top 1 a.* from __application as a
 join __navigation as n on n.applicationid = a.id
 join __roleNavigation as rn on rn.navigationid = n.id
 join __relationRoleToUser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
 where u.account={0} and a.isDefault={1} and a.type={2}";
                string sqlTop1 = @"select top 1 a.* from __application as a
 join __navigation as n on n.applicationid = a.id
 join __roleNavigation as rn on rn.navigationid = n.id
 join __relationRoleToUser as ru on ru.roleid = rn.roleid
 join __user as u on u.id = ru.userid
 where u.account={0} and a.type={1}";
                Application application = context.Database.SqlQuery<Application>(sqlDefault, account, true, type).SingleOrDefault();
                if (application == null)
                {
                    application = context.Database.SqlQuery<Application>(sqlTop1, account, type).SingleOrDefault();
                }
                return application;
            }
        }

        public bool DeleteApplication(Guid applicationId)
        {
            Logger.Info("core", string.Format("begin delete application:{0}", applicationId));

            using (CoreContext context = _contextFactory.Get())
            {
                Application application = context.Set<Application>().Where(p => p.Id == applicationId).SingleOrDefault();
                if (application != null)
                {
                    context.Entry(application).State = System.Data.Entity.EntityState.Deleted;
                    if (context.SaveChanges() > 0)
                    {
                        Logger.Info("core", string.Format("delete application:{0} success", applicationId));
                        return true;
                    }
                }
                else
                {
                    Logger.Info("core", string.Format("delete application:{0} success, this application does not exist in the database", applicationId));
                    return true;
                }
            }
            Logger.Info("core", string.Format("delete application:{0} failure", applicationId));
            return false;
        }

        public bool AddModule(Guid applicationId, Guid moduleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<ApplicationModule>()
                    .Where(p => p.ApplicationId == applicationId && p.ModuleId == moduleId)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() == null)
                {
                    ApplicationModule model = new ApplicationModule();
                    model.Id = Guid.NewGuid();
                    model.ApplicationId = applicationId;
                    model.ModuleId = moduleId;
                    context.Set<ApplicationModule>().Add(model);

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        public bool RemoveModule(Guid applicationId, Guid moduleId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                ApplicationModule model = context.Set<ApplicationModule>()
                    .Where(p => p.ApplicationId == applicationId && p.ModuleId == moduleId)
                    .FirstOrDefault();

                if (model != null)
                {
                    context.Entry(model).State = System.Data.Entity.EntityState.Deleted;

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }
        }

        public List<Module> GetModules(Guid applicationId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Module> list = new List<Module>();
                List<Module> modules = context.Set<Module>()
                    .Include("Views")
                    .ToList();
                List<ApplicationModule> appModules = context.Set<ApplicationModule>()
                    .Where(p=>p.ApplicationId == applicationId).ToList();

                foreach (var module in modules)
                {
                    foreach (var am in appModules)
                    {
                        if (module.Id == am.ModuleId)
                        {
                            list.Add(module);
                            break;
                        }
                    }
                }

                return list;
            }
        }
        #endregion

        #region theme

        public bool SaveTheme(Theme theme)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<Theme>()
                    .Where(p => p.Id == theme.Id)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() == null)
                {
                    context.Set<Theme>().Add(theme);
                }
                else
                {
                    context.Entry(theme).State = System.Data.Entity.EntityState.Modified;
                }

                if (context.SaveChanges() > 0)
                {
                    return true;
                } 
                return false;
            }
        }

        public List<Theme> GetThemes()
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Theme>().ToList();
            }
        }

        public List<Theme> GetThemes(string type)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Theme>().Where(p => p.Type == type).ToList();
            }
        }

        public Theme GetTheme(Guid themeId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<Theme>().Where(p => p.Id == themeId).FirstOrDefault();
            }
        }
        #endregion

        #region Image
        public bool SaveImage(ImageFile image)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                if (context.Set<ImageFile>()
                    .Where(p => p.Id == image.Id)
                    .Select(p => new { p.Id })
                    .FirstOrDefault() == null)
                {
                    context.Set<ImageFile>().Add(image);
                }
                else
                {
                    context.Set<ImageFile>().Attach(image);
                }

                if (context.SaveChanges() > 0)
                {
                    return true;
                }
                return false;
            }
        }

        public bool DeleteImage(Guid imageId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                ImageFile image = context.Set<ImageFile>()
                    .Where(p => p.Id == imageId).FirstOrDefault();
                if (image != null)
                {
                    context.Entry(image).State = System.Data.Entity.EntityState.Deleted;

                    if (context.SaveChanges() > 0)
                    {
                        return true;
                    }
                }
                return false;
            }
        }

        public ImageFile GetImage(Guid imageId)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<ImageFile>().Where(p => p.Id == imageId).SingleOrDefault();
            }
        }

        public List<ImageFile> GetImages()
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return context.Set<ImageFile>()
                    .Select(p => new ImageFile { Id = p.Id, Extension = p.Extension, SortIndex = p.SortIndex })
                    .ToList();
            }
        }
        #endregion

        #region privilege

        public bool SavePrivilege(Privilege privilege)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return EntityRepository.Save(privilege, context.DbContext);
            }
        }

        public bool DeletePrivilege(Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return EntityRepository.Delete(id, context.DbContext);
            }
        }

        public Privilege GetPrivilege(Guid id)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                return EntityRepository.Get(id, context.DbContext) as Privilege;
            }
        }

        public PagedList<Privilege> GetPrivileges(string type, int start, int limit)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Privilege> list = null;
                if (string.IsNullOrEmpty(type))
                {
                    list = context.Set<Privilege>()
                        .OrderBy(p => p.Code)
                        .Take(limit)
                        .Skip(start)
                        .ToList();
                }
                else
                {
                    list = context.Set<Privilege>().Where(p => p.Type == type)
                        .OrderBy(p => p.Code)
                        .Take(limit)
                        .Skip(start)
                        .ToList();
                }

                int totalCount = context.Set<Privilege>().Where(p => p.Type == type).Count();

                PagedList<Privilege> pagedList = new PagedList<Privilege>();
                pagedList.AddRange(list);
                pagedList.Start = start;
                pagedList.Limit = limit;
                pagedList.Total = totalCount;
                return pagedList;
            }
        }

        public PagedList<Privilege> FindPrivileges(string code, int start, int limit)
        {
            using (CoreContext context = _contextFactory.Get())
            {
                List<Privilege> list = context.Set<Privilege>().Where(p => p.Code.Contains(code))
                    .OrderBy(p => p.Code)
                    .Take(limit)
                    .Skip(start)
                    .ToList();

                int totalCount = context.Set<Privilege>().Where(p => p.Code.Contains(code)).Count();

                PagedList<Privilege> pagedList = new PagedList<Privilege>();
                pagedList.AddRange(list);
                pagedList.Start = start;
                pagedList.Limit = limit;
                pagedList.Total = totalCount;
                return pagedList;
            }
        }
        #endregion
    }
}
